Compute the length of a string literal, which behaves like String#length.
計算字串常值的長度,行為類似於 String#length
。
type L = LengthOfString<'test'> // 4
你的任務是讓下面的type cases測試通過:
type cases = [
Expect<Equal<LengthOfString<''>, 0>>,
Expect<Equal<LengthOfString<'kumiko'>, 6>>,
Expect<Equal<LengthOfString<'reina'>, 5>>,
Expect<Equal<LengthOfString<'Sound! Euphonium'>, 16>>,
]
從以下幾個方向來思考:
遞迴解法 (Recursive Approach):透過遞迴,我們可以逐字元地處理字串,然後累計長度。想像成我們每次拆解字串的一個字元,剩下的部分繼續遞迴處理,直到字串被完全拆解,最終我們累加所有的字元數量。
字串模板類型 (Template Literal Types):透過 TypeScript 的模板字串功能,我們可以使用字串模式匹配(pattern matching)來分割字串,然後逐步對每個字元進行遞迴處理。這樣可以將字串的一部分提取出來並進行處理,然後再處理剩餘部分。
陣列和長度 (Array and Length):要計算字串的長度,我們可以使用陣列來記錄每次遞迴步驟中所累積的字元。當字串完全被處理後,陣列中存放的就是字元的數量,最後只需要取出這個陣列的長度來計算字串的總長度。
解法1:
type LengthOfString<
S extends string,
T extends string[] = []
> = S extends `${infer F}${infer R}`
? LengthOfString<R, [...T, F]>
: T['length'];
細節分析:
類型定義 (Type Definition):
LengthOfString<S extends string, T extends string[]
= []> 定義了一個型別 LengthOfString
,它接受一個字串 S
作為輸入,並且使用一個默認的空陣列 T
來累計字元的數量。模板字串和遞迴 (Template Literals and Recursion):
S extends ${infer F}${infer R}
S
拆解成兩部分:F
是字串的第一個字元,R
是剩餘的字串。每次遞迴都會將 F
添加到累計陣列 T
中,然後對剩餘的字串 R
進行下一步遞迴。累積結果 (Accumulate Result):
- [...T, F]
:
每次遞迴時,我們將新的字元 F
添加到累積陣列 T
中,通過擴展運算符來構建一個新陣列,包含了所有已處理過的字元。
基礎情況 (Base Case):
S
被完全拆解為空字串(即不再符合模板字串的分割條件)時,遞迴停止,直接返回累積陣列 T
的長度 T['length']
,這就是最終的字串長度。解法2:
type StrToArray<S> = S extends `${infer x}${infer xs}` ? [1, ...StrToArray<xs>] : [];
type LengthOfString<S extends string> = StrToArray<S>['length'];
細節分析:
字串轉換為陣列 (String to Array)
StrToArray<S>
將字串 S
逐步拆分為陣列。通過模板字串類型,S
被拆解為第一個字元 x
和剩餘的字串 xs
。每次遞迴時,將數字 1(代表一個字元)加入陣列,並繼續處理剩餘的字串 xs
。基礎情況 (Base Case)
S
被完全拆解(即 S
不再匹配模板字串類型),遞迴停止,並返回一個空陣列 []
。這是遞迴的結束條件。計算長度 (Calculate Length)
LengthOfString<S extends string>
使用了 StrToArray<S>['length']
來計算字串對應的陣列長度。由於每個遞迴步驟中都會將 1 添加到陣列中,因此陣列的長度就是字串的長度。這樣,我們就能順利通過測試啦 🎉 😭 🎉
本次介紹了 Length of String
的實作,下一關會挑戰 Flatten
,期待再相見!